<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>SpringMVC学习笔记 | 后端学习记录</title><meta name="keywords" content="Spring"><meta name="author" content="h0ss"><meta name="copyright" content="h0ss"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="1、概述在了解SpringMVC之前，我们需要知道MVC架构设计模式以及J2EE的三层架构设计，MVC模式如下图所示：  三层结构如下图所示：  SpringMVC则是基于 MVC 设计理念的 Web 框架，集成于SpringFramework中。SpringMVC也就是我们熟知的’SSM’中的’S’，它通过一套 MVC 注解，让 POJO 成为处理请求的控制器，而无须实现任何接口，并且支持RES">
<meta property="og:type" content="article">
<meta property="og:title" content="SpringMVC学习笔记">
<meta property="og:url" content="https://blog.gpnusz.cn/2021/08/01/SpringMVC%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/index.html">
<meta property="og:site_name" content="后端学习记录">
<meta property="og:description" content="1、概述在了解SpringMVC之前，我们需要知道MVC架构设计模式以及J2EE的三层架构设计，MVC模式如下图所示：  三层结构如下图所示：  SpringMVC则是基于 MVC 设计理念的 Web 框架，集成于SpringFramework中。SpringMVC也就是我们熟知的’SSM’中的’S’，它通过一套 MVC 注解，让 POJO 成为处理请求的控制器，而无须实现任何接口，并且支持RES">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://static01.imgkr.com/temp/07cc3f2f859f40ef8733044657da8465.jpg">
<meta property="article:published_time" content="2021-08-01T12:40:45.000Z">
<meta property="article:modified_time" content="2022-07-28T07:11:30.555Z">
<meta property="article:author" content="h0ss">
<meta property="article:tag" content="Spring">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://static01.imgkr.com/temp/07cc3f2f859f40ef8733044657da8465.jpg"><link rel="shortcut icon" href="/img/favicon.png"><link rel="canonical" href="https://blog.gpnusz.cn/2021/08/01/SpringMVC%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: undefined,
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    jQuery: 'https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js',
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/js/jquery.justifiedGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/css/justifiedGallery.min.css'
    },
    fancybox: {
      js: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.js',
      css: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isanchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = { 
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: false,
  postUpdate: '2022-07-28 15:11:30'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    })(window)</script><meta name="generator" content="Hexo 5.4.0"><link rel="stylesheet" href="/css/prism-tomorrow.css" type="text/css"></head><body><div id="web_bg"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="author-avatar"><img class="avatar-img" src="/img/avatar.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="site-data"><div class="data-item is-center"><div class="data-item-link"><a href="/archives/"><div class="headline">文章</div><div class="length-num">51</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a></div></div></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="not-top-img" id="page-header"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">后端学习记录</a></span><div id="menus"><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav></header><main class="layout" id="content-inner"><div id="post"><div id="post-info"><h1 class="post-title">SpringMVC学习笔记</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2021-08-01T12:40:45.000Z" title="发表于 2021-08-01 20:40:45">2021-08-01</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2022-07-28T07:11:30.555Z" title="更新于 2022-07-28 15:11:30">2022-07-28</time></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">6.2k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>23分钟</span></span></div></div></div><article class="post-content" id="article-container"><h2 id="1、概述"><a href="#1、概述" class="headerlink" title="1、概述"></a>1、概述</h2><p>在了解SpringMVC之前，我们需要知道MVC架构设计模式以及J2EE的三层架构设计，MVC模式如下图所示：</p>
<p><img src="https://www.hualigs.cn/image/61041819b4454.jpg"></p>
<p>三层结构如下图所示：</p>
<p><img src="https://i.loli.net/2021/07/31/TAZyk5fiRrcDdzt.png"></p>
<p>SpringMVC则是基于 MVC 设计理念的 Web 框架，集成于SpringFramework中。SpringMVC也就是我们熟知的’SSM’中的’S’，它通过一套 MVC 注解，让 POJO 成为处理请求的控制器，而无须实现任何接口，并且支持REST风格URL，整体采用松散耦合、可插拔组件结构，比其他 MVC 框架更具扩展性和灵活性。</p>
<p>SpringMVC 基于 Servlet 规范实现，所以基于 SpringMVC 的项目，需要 Servlet 容器服务器支撑，比如常用的tomcat。</p>
<h2 id="2、快速上手"><a href="#2、快速上手" class="headerlink" title="2、快速上手"></a>2、快速上手</h2><h3 id="1）环境准备"><a href="#1）环境准备" class="headerlink" title="1）环境准备"></a>1）环境准备</h3><p>首先需要导入项目所需要的maven依赖，包括spring-web、spring-webmvc、servlet-api、jsp相关依赖、IoC相关依赖。基本环境为Spring5.1.3.RELEASE，tomcat8。</p>
<h3 id="2）逻辑代码"><a href="#2）逻辑代码" class="headerlink" title="2）逻辑代码"></a>2）逻辑代码</h3><h4 id="①控制器类"><a href="#①控制器类" class="headerlink" title="①控制器类"></a>①控制器类</h4><p>首先需要创建一个用于分发请求的控制器类，在SpringMVC中只要给类标上<code>@Controller</code> 注解即表示这是个控制器类，之后使用<code>@RequestMapping</code> 注解在方法上标明请求路径，方法的返回值即是对应的视图页面(这里以jsp为例)。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> top.jtszt.controller;</span><br><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloController</span> </span>&#123;</span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/hello&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">hello</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;/WEB-INF/pages/hello.jsp&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="②配置相关"><a href="#②配置相关" class="headerlink" title="②配置相关"></a>②配置相关</h4><p>有了<code>@Controller</code>注解标注的控制器类之后，我们还需要将组件扫描加入IoC容器中：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- SpringMVC-config.xml --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">...</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">context:component-scan</span> <span class="attr">base-package</span>=<span class="string">&quot;top.jtszt&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>SpringMVC 的核心控制器是一个 Servlet 叫 <code>DispatcherServlet</code> 。所以我们需要在 web.xml中配置它，并且需要配置对应的Spring配置文件指向与启动级别：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">servlet</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">servlet-name</span>&gt;</span>hello<span class="tag">&lt;/<span class="name">servlet-name</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">servlet-class</span>&gt;</span>org.springframework.web.servlet.DispatcherServlet<span class="tag">&lt;/<span class="name">servlet-class</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">init-param</span>&gt;</span></span><br><span class="line">		<span class="tag">&lt;<span class="name">param-name</span>&gt;</span>contextConfigLocation<span class="tag">&lt;/<span class="name">param-name</span>&gt;</span></span><br><span class="line">		<span class="tag">&lt;<span class="name">param-value</span>&gt;</span>classpath:SpringMVC-config.xml<span class="tag">&lt;/<span class="name">param-value</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;/<span class="name">init-param</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">load-on-startup</span>&gt;</span>1<span class="tag">&lt;/<span class="name">load-on-startup</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">servlet</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">servlet-mapping</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">servlet-name</span>&gt;</span>hello<span class="tag">&lt;/<span class="name">servlet-name</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">url-pattern</span>&gt;</span>/<span class="tag">&lt;/<span class="name">url-pattern</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">servlet-mapping</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>这里如果不显式配置Spring配置文件路径，默认会按照<code>classpath:&#123;servlet-name&#125;-servlet.xml</code>去查找配置文件，并且需要注意的是这里servlet的拦截路径为/，如果拦截为/*则表示连同jsp页面都拦截，而jsp是我们用来展示的，不可以进行拦截。</p>
<p>之后是配置tomcat以及jsp页面</p>
<p><img src="https://i.loli.net/2021/08/01/aMZD3w5cxNQnEmq.png" alt="image-20210731145724536.png"></p>
<h4 id="③测试"><a href="#③测试" class="headerlink" title="③测试"></a>③测试</h4><p>配置完毕，我们可以启动项目，在浏览器查看效果。</p>
<p><img src="https://i.loli.net/2021/08/01/mgrqlU3CZNL4ItS.png" alt="image-20210731145922454.png"></p>
<h2 id="3、视图解析器"><a href="#3、视图解析器" class="headerlink" title="3、视图解析器"></a>3、视图解析器</h2><h3 id="1）概述"><a href="#1）概述" class="headerlink" title="1）概述"></a>1）概述</h3><p>SpringMVC中的视图解析器（ViewResolver）是前端控制器中九大组件之一，用于将逻辑视图转化为物理视图。SpringMVC会先将控制器类的 <code>String/ModelAndView/View</code> 类型的返回值都转化为<code>ModelAndView</code> 类型，之后视图解析器把它解析为具体的<code>View</code> 类型的视图对象。</p>
<p>ViewResolver接口中有几个主要的实现类，可以实现视图解析功能：</p>
<ul>
<li>BeanNameViewResolver：将视图名解析为一个Bean</li>
<li>InternalResourceViewResolver：将视图名解析为一个URL文件</li>
<li>jasperReportsViewResolver：将视图名解析为报表文件对应的URL</li>
</ul>
<p>我们可以选择一种视图解析器或混用多种视图解析器，并且每个视图解析器都实现了 Ordered 接口并开放出一个 order 属性，可以通过 order 属性指定解析器的优先顺序，<strong>order 越小优先级越高</strong>。</p>
<h3 id="2）解析前后缀"><a href="#2）解析前后缀" class="headerlink" title="2）解析前后缀"></a>2）解析前后缀</h3><p>在对jsp页面的解析中一般使用<code>InternalResourceViewResolver</code> ，最常见的是配置视图解析的前缀和后缀，对于xml配置来说直接配置bean即可：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;prefix&quot;</span> <span class="attr">value</span>=<span class="string">&quot;/WEB-INF/pages/&quot;</span>/&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;suffix&quot;</span> <span class="attr">value</span>=<span class="string">&quot;.jsp&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>其中 <code>prefix</code> 代表解析器拼串开头，<code>suffix</code> 代表解析器拼串结尾，这样配置之后，我们在控制器类的返回只需要返回hello即可。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;WEB-INF&#x2F;pages&#x2F;hello.jsp  ---&gt;  hello</span><br></pre></td></tr></table></figure>

<h3 id="3）拼串与否？"><a href="#3）拼串与否？" class="headerlink" title="3）拼串与否？"></a>3）拼串与否？</h3><p>这里还涉及到一个返回值拼串与否的问题，正常来说返回值都是按照设定的前缀和后缀进行拼串之后返回视图，而如果出现以下两种情况，那么视图解析器将不会拼前后缀：</p>
<ul>
<li>返回值以<code>forward: </code>开头，代表的是直接转发</li>
<li>返回值以<code>redirect:</code>开头，代表的是重定向</li>
</ul>
<p>除了以上两种情况，其他的都会进行拼串处理。</p>
<h2 id="4、数据传递与参数绑定"><a href="#4、数据传递与参数绑定" class="headerlink" title="4、数据传递与参数绑定"></a>4、数据传递与参数绑定</h2><p>现在已经可以实现请求分发与响应功能了，那么如果页面的数据需要在请求时才渲染要怎么做，换句话说，数据传递要怎么办？这时可以将数据放置在request域中，在页面去取出对应的数据。传统的引入HttpServletRequest传递的方式就不介绍了，这里主要介绍SpringMVC中提供了数据传递功能。</p>
<h3 id="1）ModelAndView"><a href="#1）ModelAndView" class="headerlink" title="1）ModelAndView"></a>1）ModelAndView</h3><p><code>ModelAndView</code> 能封装数据和返回跳转的视图信息，在其中存储的数据实际上是存储在request域中。可以在参数位置传入<code>ModelAndView</code>对象，之后调用 <code>setViewName</code> 设置视图名，调用<code>addObject</code> 设置放置的数据信息(键值对) 。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/hello&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> ModelAndView <span class="title">hello</span><span class="params">(ModelAndView mv)</span> </span>&#123;</span><br><span class="line">    mv.addObject(<span class="string">&quot;msg&quot;</span>, <span class="string">&quot;this is msg from modelAndView&quot;</span>);</span><br><span class="line">    mv.setViewName(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> mv;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>也可以手动创建一个<code>ModelAndView</code>对象，传入的参数为要跳转的视图名，之后调用该对象的<code>addObject</code>方法设置数据信息。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/hello&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> ModelAndView <span class="title">hello</span><span class="params">()</span></span>&#123;</span><br><span class="line">	ModelAndView modelAndView = <span class="keyword">new</span> ModelAndView(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line">	modelAndView.addObject(<span class="string">&quot;msg&quot;</span>, <span class="string">&quot;this is msg from modelAndView&quot;</span>);</span><br><span class="line">	<span class="keyword">return</span> modelAndView;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>之后在jsp页面 <code>$&#123;msg&#125;</code> 取出即可。</p>
<p>当然这里可传入的不只是简单信息，也可以传入Map、List等，在jsp页面通过c:foreach取出即可。</p>
<h3 id="2）Map与Model"><a href="#2）Map与Model" class="headerlink" title="2）Map与Model"></a>2）Map与Model</h3><p>Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器，如果方法的入参为 Map 或 Model 类型，Spring MVC 会将隐含模型的引用传递给这些入参。</p>
<p>在方法体内，我们可以通过入参对象访问到模型中的所有数据，也可以向模型中添加新的属性数据。</p>
<p>实际上传入无论是Model、Map还是ModelMap最终都会被转化为BindingAwareModelMap对象。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/hello&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">hello</span><span class="params">(ModelMap modelMap, </span></span></span><br><span class="line"><span class="function"><span class="params">                      Map&lt;String,Object&gt; map, </span></span></span><br><span class="line"><span class="function"><span class="params">                      Model model)</span></span>&#123;</span><br><span class="line">	modelMap.addAttribute(<span class="string">&quot;msg&quot;</span>,<span class="string">&quot;hello modelMap&quot;</span>);</span><br><span class="line">	map.put(<span class="string">&quot;msg2&quot;</span>, <span class="string">&quot;hello map&quot;</span>);</span><br><span class="line">	model.addAttribute(<span class="string">&quot;msg3&quot;</span>,<span class="string">&quot;hello model&quot;</span>);</span><br><span class="line">	<span class="keyword">return</span> <span class="string">&quot;hello&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="3）参数收集"><a href="#3）参数收集" class="headerlink" title="3）参数收集"></a>3）参数收集</h3><h4 id="①-原生数据类型"><a href="#①-原生数据类型" class="headerlink" title="① 原生数据类型"></a>① 原生数据类型</h4><p>这种类型的数据除了可以在入参位置声明 <code>HttpServletRequest</code> ，之后通过<code>request.getParameter()</code> 获取参数之外，还可以直接在入参位置传入需要获取的参数。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/hello&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">hello</span><span class="params">(HttpServletRequest request)</span> </span>&#123;</span><br><span class="line">    String name = request.getParameter(<span class="string">&quot;name&quot;</span>);</span><br><span class="line">    System.out.println(<span class="string">&quot;name is &quot;</span>+ name);</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;result&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/hello&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">hello</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;name is &quot;</span>+ name);</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;result&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>当我们访问 <code>/hello?name=&quot;test&quot;</code> 时就可以在控制器中成功打印结果。</p>
<h4 id="②模型类型"><a href="#②模型类型" class="headerlink" title="②模型类型"></a>②模型类型</h4><p>假设有一个Employee对象，包含id和name属性，现在我们需要将参数中的name与id获取之后包装成Employee对象，这时我们不需要手动进行包装。在SpringMVC中，如果请求的参数名称，与模型类中的属性一一对应，那么SpringMVC 会按请求参数名和 POJO 属性名进行自动匹配，自动为该对象填充属性值，支持级联属性。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/hello&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">hello</span><span class="params">(Employee employee)</span> </span>&#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;Employee is &quot;</span>+ employee);</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;result&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>当我们访问 <code>/hello?id=1&amp;name=&quot;test&quot;</code> 时就可以在控制器中成功打印结果。</p>
<h4 id="③使用注解"><a href="#③使用注解" class="headerlink" title="③使用注解"></a>③使用注解</h4><p>在SpringMVC中还可以通过 <code>@RequestParam</code> 注解获取参数，这种获取方式不要求用户传参与规定参数一一对应，可以指定参数名获取。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/hello&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">hello</span><span class="params">(<span class="meta">@RequestParam(&quot;username&quot;)</span>String name)</span> </span>&#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;name is &quot;</span>+ name);</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;result&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这时访问 <code>/hello?username=&quot;test&quot;</code> 时也可以在控制器中成功打印结果。</p>
<p>现在我们解决了参数名不一致的获取问题，那么如果不带参数访问呢？实测会抛异常，因为默认是需要传入参数的。为此该注解还有一个属性：<code>required</code> ，它表示请求参数中是否必须携带指定的参数。默认值是 true 。还有一个属性 <code>defaultValue</code>，它可以指定参数不传递时的默认值。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/hello&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">hello</span><span class="params">(<span class="meta">@RequestParam(value = &quot;username&quot;,required = false,defaultValue = &quot;default&quot;)</span>String name)</span> </span>&#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;name is &quot;</span>+ name);</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;result&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这时访问 <code>/hello</code> 也不会抛异常，并且会打印default。</p>
<h4 id="④其他注解"><a href="#④其他注解" class="headerlink" title="④其他注解"></a>④其他注解</h4><p>除了获取参数的注解，SpringMVC中还有用于获取header的某个属性值的注解 <code>@RequestHeader</code>，以及获取cookie中的某个属性值的注解 <code>@CookieValue</code>。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/hello&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">hello</span><span class="params">(<span class="meta">@RequestHeader(&quot;User-Agent&quot;)</span>String userAgent,</span></span></span><br><span class="line"><span class="function"><span class="params">                    <span class="meta">@CookieValue(&quot;JSESSIONID&quot;)</span>String jid)</span></span>&#123;&#125;</span><br></pre></td></tr></table></figure>

<h3 id="4）乱码问题"><a href="#4）乱码问题" class="headerlink" title="4）乱码问题"></a>4）乱码问题</h3><p>在接收POST请求参数时，可能会出现中文乱码的问题，这是编码集不一致导致的。SpringMVC中提供了<code>CharacterEncodingFilter</code> 用于解决乱码问题，它有三个属性，<code>encoding</code> 代表编码格式， <code>forceRequestEncoding</code> 代表对请求设置编码， <code>forceResponseEncoding</code> 代表对响应设置编码。这里我们只需要在<code>web.xml</code>中配置好这个filter，并且设置拦截路径为 <code>/*</code> 即可。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">web-app</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">filter</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">filter-name</span>&gt;</span>characterEncodingFilter<span class="tag">&lt;/<span class="name">filter-name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">filter-class</span>&gt;</span>org.springframework.web.filter.CharacterEncodingFilter<span class="tag">&lt;/<span class="name">filter-class</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">init-param</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">param-name</span>&gt;</span>encoding<span class="tag">&lt;/<span class="name">param-name</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">param-value</span>&gt;</span>UTF-8<span class="tag">&lt;/<span class="name">param-value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">init-param</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">init-param</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">param-name</span>&gt;</span>forceResponseEncoding<span class="tag">&lt;/<span class="name">param-name</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">param-value</span>&gt;</span>true<span class="tag">&lt;/<span class="name">param-value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">init-param</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">init-param</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">param-name</span>&gt;</span>forceRequestEncoding<span class="tag">&lt;/<span class="name">param-name</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">param-value</span>&gt;</span>true<span class="tag">&lt;/<span class="name">param-value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">init-param</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">filter</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">filter-mapping</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">filter-name</span>&gt;</span>characterEncodingFilter<span class="tag">&lt;/<span class="name">filter-name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">url-pattern</span>&gt;</span>/*<span class="tag">&lt;/<span class="name">url-pattern</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">filter-mapping</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">web-app</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>如果是GET请求出现乱码问题，那应该考虑的是Tomcat的编码设置问题。</p>
<h2 id="5、请求映射"><a href="#5、请求映射" class="headerlink" title="5、请求映射"></a>5、请求映射</h2><p>SpringMVC中使用 <code>@RequestMapping</code> 注解为控制器指定可以处理哪些 URL 请求，这个注解可以标注在类上，也可以标注在方法上。如果<code>@RequestMapping(&quot;/admin&quot;)</code> 标注在类上，那么该类下的所有方法都须以 <code>/admin</code> 为前缀才可以访问。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//如：</span></span><br><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/admin&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyController</span> </span>&#123;&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/hello&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">hello</span><span class="params">()</span> </span>&#123;<span class="keyword">return</span> <span class="string">&quot;hello&quot;</span>&#125;</span><br></pre></td></tr></table></figure>

<p>那么如果要访问到hello.jsp页面必须通过 <code>/admin/hello</code> 访问。</p>
<p>此外 <code>@RequestMapping</code> 中也提供了对于请求头的一些限制属性，其中 value 表示请求URL，method 表示请求方法，params 代表请求参数，heads 表示请求头，他们之间是与的关系，联合使用多个条件可让请求映射更加精确化。</p>
<p>此外SpringMVC也提供了几个限定请求方式的注解：</p>
<ul>
<li>@GetMapping(“xx”) ：限定get方式</li>
<li>@PostMapping(“xx”) ：限定post方式</li>
<li>@PutMapping(“xx”)：限定put方式</li>
<li>@DeleteMapping(“xx”)：限定delete方式</li>
</ul>
<h2 id="6、RESTful风格"><a href="#6、RESTful风格" class="headerlink" title="6、RESTful风格"></a>6、RESTful风格</h2><p>REST即Representational State Transfer(表现层状态转化)，是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便，所以正得到越来越多网站的采用。</p>
<p>每发出一个请求，就代表了客户端和服务器的一次交互过程。HTTP协议，是一个无状态协议，即所有的状态都保存在服务器端。因此，如果客户端想要操作服务器，必须通过某种手段，让服务器端发生“状态转化”。而这种转化是建立在表现层之上的，所以就是 “表现层状态转化”。</p>
<p>具体说，就是 HTTP 协议里面，四个表示操作方式的动词：GET、POST、PUT、DELETE。它们分别对应四种基本操作：GET 用来获取资源，POST 用来新建资源，PUT 用来更新资源，DELETE 用来删除资源。而RESTful风格就是将这四种方式与资源的操作联系起来。</p>
<p>举个例子，假设现在要实现员工信息的增删改查，那RESTful风格的url就可以是下面这样的：</p>
<ul>
<li>员工列表：/emps       get方法</li>
<li>员工添加：/emp        post方法</li>
<li>员工修改：/emp/{id}   put方法</li>
<li>员工删除：/emp/{id}   delete方法</li>
<li>员工查询：/emp/{id}   get方法</li>
</ul>
<p>这里的{id}代表的是动态的id传入，在SpringMVC中可以使用<code>@PathVariable(&quot;id&quot;)</code>标注在Controller的参数位置来获取URL中的指定的值。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(value = &quot;/emp/&#123;id&#125;&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">getEmp</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span>Integer id)</span></span>&#123;...&#125;</span><br></pre></td></tr></table></figure>

<p>这样当我们以GET方式访问<code>/emp/1</code> 时，在getEmp方法中就可以拿到具体的id。</p>
<h2 id="7、返回json数据"><a href="#7、返回json数据" class="headerlink" title="7、返回json数据"></a>7、返回json数据</h2><h3 id="1）导包、配置"><a href="#1）导包、配置" class="headerlink" title="1）导包、配置"></a>1）导包、配置</h3><p>SpringMVC中整合了主流的json转换工具，默认使用 jackson 进行 json 格式转换。使用jackson需要先导入maven依赖，包括：<code>jackson-core、jackson-annotations、jackson-databind</code>。导入依赖之后还需要配置json转换器，一种比较简单的方法是在SpringMVC的配置文件中加入注解驱动配置，也可以手动配置。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 开启注解驱动 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">mvc:annotation-driven</span>/&gt;</span></span><br></pre></td></tr></table></figure>

<h3 id="2）-ResponseBody"><a href="#2）-ResponseBody" class="headerlink" title="2）@ResponseBody"></a>2）@ResponseBody</h3><p>此外还需要在Controller对应方法上标注 <code>@ResponseBody</code> ，表明方法返回信息作为响应体返回（由jackson包封装为json格式）。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//假数据做示例</span></span><br><span class="line">Employee emp = <span class="keyword">new</span> Employee(<span class="number">1</span>, <span class="string">&quot;test01&quot;</span>, <span class="string">&quot;123@163.com&quot;</span>);</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ResponseBody</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/getinfo&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Employee <span class="title">getInfo</span><span class="params">()</span></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> emp;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>还可以将返回值类型设置成<code>ResponseEntity&lt;T&gt;</code> ，之后在方法中new该对象，以此方法可以设置响应体、响应头以及响应状态码。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/getinfo2&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> ResponseEntity&lt;Employee&gt; <span class="title">getInfo2</span><span class="params">()</span></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> ResponseEntity&lt;&gt;(emp,HttpStatus.OK);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="3）-RestController"><a href="#3）-RestController" class="headerlink" title="3）@RestController"></a>3）@RestController</h3><p>当一个Controller类中的所有映射方法都要返回json数据，那么在每个方法上都标注上<code>@ResponseBody</code> 注解就不太现实了。这时可以直接在类上标注<code>@ResponseBody</code> ，也可以使用<code>@RestController</code>注解标注在Controller类上，其相当于<code>@Controller</code> 与 <code>@ResponseBody</code>。</p>
<h3 id="4）-RequestBody"><a href="#4）-RequestBody" class="headerlink" title="4）@RequestBody"></a>4）@RequestBody</h3><p>与 <code>@ResponseBody</code>相对的还有 <code>@RequestBody</code>，它可以把请求体中json格式的数据封装成指定的对象。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/saveinfo&quot;)</span></span><br><span class="line"><span class="meta">@ResponseBody</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">saveInfo</span><span class="params">(<span class="meta">@RequestBody</span> Employee employee)</span> </span>&#123;</span><br><span class="line">	System.out.println(employee);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p> 当我们POST此路径并带上json格式的数据时，其会将请求体中的数据（如果存在配对）封装成Employee对象。</p>
<p>除此之外还可以将参数声明为 <code>HttpEntity&lt;T&gt;</code> ，这样声明的参数除了可以获得请求体还可以获得请求头。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/saveinfo2&quot;)</span></span><br><span class="line"><span class="meta">@ResponseBody</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">saveInfo</span><span class="params">(HttpEntity&lt;Employee&gt; httpEntity)</span> </span>&#123;</span><br><span class="line">	Employee emp = httpEntity.getBody();</span><br><span class="line">	System.out.println(emp);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="8、静态资源配置"><a href="#8、静态资源配置" class="headerlink" title="8、静态资源配置"></a>8、静态资源配置</h2><h3 id="1）默认处理器"><a href="#1）默认处理器" class="headerlink" title="1）默认处理器"></a>1）默认处理器</h3><p>如果我们尝试引入项目路径下的js或者css，会发现并不能访问到。这个问题源于我们将SpringMVC中的<code>DispatcherServlet</code> 请求映射配置为 /，这时静态资源的请求也会被当成一个普通请求处理，因找不到对应处理器而导致错误。</p>
<p>这时可以在 SpringMVC 的配置文件中配置默认处理器解决静态资源的问题：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">mvc:default-servlet-handler</span>/&gt;</span> </span><br></pre></td></tr></table></figure>

<p>起作用的是 SpringMVC 上下文中定义的 <code>DefaultServletHttpRequestHandler</code>，它会对进入 <code>DispatcherServlet</code> 的请求进行筛查，如果发现是没有经过映射的请求，就将该请求交由 WEB 应用服务器默认的 Servlet 处理；如果不是静态资源的请求，才由 DispatcherServlet 继续处理<br>一般 WEB 应用服务器默认的 Servlet 的名称都是 default。若所使用的 WEB 服务器的默认 Servlet 名称不是 default，则需要通过 <code>default-servlet-name</code> 属性显式指定</p>
<h3 id="2）解析配置"><a href="#2）解析配置" class="headerlink" title="2）解析配置"></a>2）解析配置</h3><p>除了使用默认处理器解析之外，还可以显式地配置上对于静态资源的解析。通过xml<code>&lt;mvc:resources&gt;</code>标签进行配置，其中<code>cache-period</code> 表示缓存时长。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">mvc:resources</span> <span class="attr">mapping</span>=<span class="string">&quot;/js/**&quot;</span> <span class="attr">location</span>=<span class="string">&quot;/scripts/&quot;</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">mvc:resources</span> <span class="attr">mapping</span>=<span class="string">&quot;/css/**&quot;</span> <span class="attr">location</span>=<span class="string">&quot;/css/&quot;</span> <span class="attr">cache-period</span>=<span class="string">&quot;2592000&quot;</span> /&gt;</span></span><br></pre></td></tr></table></figure>

<p>这时js文件的访问会解析到项目的scripts目录，css会解析到css目录。</p>
<h2 id="9、文件上传与下载"><a href="#9、文件上传与下载" class="headerlink" title="9、文件上传与下载"></a>9、文件上传与下载</h2><h3 id="1）文件上传"><a href="#1）文件上传" class="headerlink" title="1）文件上传"></a>1）文件上传</h3><h4 id="①导依赖"><a href="#①导依赖" class="headerlink" title="①导依赖"></a>①导依赖</h4><p>首先需要导入文件上传所需的依赖，包括commons-fileupload，commons-io，以及IoC、MVC相关依赖。</p>
<h4 id="②写配置"><a href="#②写配置" class="headerlink" title="②写配置"></a>②写配置</h4><p>在基于xml的配置中，需要先配置一个文件上传处理器(CommonsMultipartResolver)，其中的<code>defaultEncoding</code> 可以用于设置文件的编码，<code> maxUploadSize</code> 可以用于设置文件大小的最大值，要注意的是配置的bean的id必须为<code>multipartResolver</code>，否则无法识别到。 </p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;multipartResolver&quot;</span> <span class="attr">class</span>=<span class="string">&quot;org.springframework.web.multipart.commons.CommonsMultipartResolver&quot;</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;defaultEncoding&quot;</span> <span class="attr">value</span>=<span class="string">&quot;UTF-8&quot;</span>/&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;maxUploadSize&quot;</span> <span class="attr">value</span>=<span class="string">&quot;#&#123;1024*1024*20&#125;&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h4 id="③接收文件"><a href="#③接收文件" class="headerlink" title="③接收文件"></a>③接收文件</h4><p>现在写一个jsp页面加上包含上传文件的表单，访问路径为项目下的/upload：</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;form action=<span class="string">&quot;$&#123;ctp&#125;/upload&quot;</span> method=<span class="string">&quot;post&quot;</span> enctype=<span class="string">&quot;multipart/form-data&quot;</span>&gt;</span><br><span class="line">    文件上传：&lt;input type=<span class="string">&quot;file&quot;</span> name=<span class="string">&quot;uploadFile&quot;</span>/&gt;</span><br><span class="line">    &lt;input type=<span class="string">&quot;submit&quot;</span> value=<span class="string">&quot;提交&quot;</span>/&gt;</span><br><span class="line">&lt;/form&gt;</span><br></pre></td></tr></table></figure>

<p>在Controller层我们写一个用于处理/upload请求的方法，这里传入一个 <code>MultipartFile</code> 类型的参数用于接收上传的文件：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UploadController</span> </span>&#123;</span><br><span class="line">    <span class="meta">@PostMapping(&quot;/upload&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">upload</span><span class="params">(<span class="meta">@RequestParam(&quot;uploadFile&quot;)</span>MultipartFile file)</span></span>&#123;...&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="④保存文件"><a href="#④保存文件" class="headerlink" title="④保存文件"></a>④保存文件</h4><p>MultipartFile有一个 <code>getOriginalFilename</code> 方法可以用于获取文件原始文件名，如果将文件保存到本地可调用MultipartFile的 <code>transferTo()</code> ，传入new File(xx) 之后即可持久化到本地。如果想保存到数据库，可获取文件的字节码存入。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">file.transferTo(<span class="keyword">new</span> File(<span class="string">&quot;I:\\upload\\&quot;</span>+filename));</span><br><span class="line"><span class="keyword">byte</span>[] bytes = file.getBytes();</span><br></pre></td></tr></table></figure>



<h3 id="2）文件下载"><a href="#2）文件下载" class="headerlink" title="2）文件下载"></a>2）文件下载</h3><p>文件的下载需要借助之前写到的<code>ResponseEntity&lt;&gt;</code> 将文件的byte[] 数据放置在其中，之后设置响应头然后返回这个对象，这里演示的是图片的展示。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DownloadController</span> </span>&#123;</span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/getImg&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> ResponseEntity&lt;<span class="keyword">byte</span>[]&gt; getImg() <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        String filename = <span class="string">&quot;I:\\upload\\mvc.png&quot;</span>;</span><br><span class="line">        <span class="keyword">byte</span>[] bytes = Files.readAllBytes(Paths.get(filename));</span><br><span class="line">        HttpHeaders headers = <span class="keyword">new</span> HttpHeaders();</span><br><span class="line">        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);</span><br><span class="line">        headers.setContentDispositionFormData(<span class="string">&quot;attachment&quot;</span>, filename);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> ResponseEntity&lt;&gt;(bytes, headers, HttpStatus.CREATED);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在jsp页面用一个img标签接收即可。</p>
<figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;img src=<span class="string">&quot;$&#123;pageContext.request.contextPath&#125;/getImg&quot;</span>&gt;</span><br></pre></td></tr></table></figure>



<h2 id="10、异常处理器"><a href="#10、异常处理器" class="headerlink" title="10、异常处理器"></a>10、异常处理器</h2><p>到目前为止，我们所有的异常都是直接抛出去，当我们用get方法访问一个限制POST方法访问的路径时，得到的是Tomcat的异常页面，这对于用户体验十分不友好并且存在代码安全性问题。因此我们需要让DispatcherServlet(前端控制器)，去对异常进行处理。</p>
<p>Spring MVC 通过 <code>HandlerExceptionResolver</code>  处理程序的异常，包括 Handler 映射、数据绑定以及目标方法执行时发生的异常，它有四个主要的实现类可以对异常进行处理：</p>
<ul>
<li>ExceptionHandlerExceptionResolver</li>
<li>ResponseStatusExceptionResolver</li>
<li>DefaultHandlerExceptionResolver</li>
<li>SimpleMappingExceptionResolver</li>
</ul>
<h3 id="1）ExceptionHandlerExceptionResolver"><a href="#1）ExceptionHandlerExceptionResolver" class="headerlink" title="1）ExceptionHandlerExceptionResolver"></a>1）ExceptionHandlerExceptionResolver</h3><p>这个异常解析器主要是处理标明 <code>@ExceptionHandle </code>注解的异常，而<code>@ExceptionHandler</code> 是SpringMVC提供的注解，用于声明式地捕获指定的异常。该注解的标注可分为两种类型：一种是在标明@controller的类中配置，也称为本类配置；一种是在单独的类中配置，也称为全局配置。</p>
<h4 id="①本类配置"><a href="#①本类配置" class="headerlink" title="①本类配置"></a>①本类配置</h4><p>在类中创建一个方法标注上<code>@ExceptionHandle(value=&quot;xx&quot;) </code>注解，value属性指明需要捕获的异常，该方法的返回值会被视图解析器解析，如果想获取异常信息可以在入参位置传入异常类型。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ExceptionHandler(value = &#123;NullPointerException.class&#125; )</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> ModelAndView <span class="title">exceptionHandle</span><span class="params">(NullPointerException npe)</span></span>&#123;</span><br><span class="line">    npe.printStackTrace();</span><br><span class="line">    ModelAndView mv = <span class="keyword">new</span> ModelAndView(<span class="string">&quot;error&quot;</span>);</span><br><span class="line">    mv.addObject(<span class="string">&quot;exception&quot;</span>,npe.getMessage());</span><br><span class="line">    <span class="keyword">return</span> mv;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="②全局配置"><a href="#②全局配置" class="headerlink" title="②全局配置"></a>②全局配置</h4><p>创建一个用于处理异常的类，在类上标注 <code>@ControllerAdvice</code> ，表明这个类用来集中处理异常；接下在定义异常处理的方法，步骤与本类配置一致。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ControllerAdvice</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ExceptionController</span> </span>&#123;</span><br><span class="line">    <span class="meta">@ExceptionHandler(value = &#123;NullPointerException.class&#125;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ModelAndView <span class="title">exceptionHandle</span><span class="params">(NullPointerException npe)</span></span>&#123;</span><br><span class="line">        npe.printStackTrace();</span><br><span class="line">        ModelAndView mv = <span class="keyword">new</span> ModelAndView(<span class="string">&quot;error&quot;</span>);</span><br><span class="line">        mv.addObject(<span class="string">&quot;exception&quot;</span>,npe.getMessage());</span><br><span class="line">        <span class="keyword">return</span> mv;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>如果全局和本类都有配置异常处理，那么本类的优先；如果捕获异常的处理器有多个，那么精确的优先。</p>
<h3 id="2）ResponseStatusExceptionResolver"><a href="#2）ResponseStatusExceptionResolver" class="headerlink" title="2）ResponseStatusExceptionResolver"></a>2）ResponseStatusExceptionResolver</h3><p>其用于处理标明 <code>@ResponseStatus</code> 注解的异常，可以自定义错误代码和错误原因，其中reason属性为错误原因，value属性与code为HttpStatus类型的错误代码。该注解主要是标注在自定义异常类上，之后在代码逻辑异常处理处抛出该错误类型，SpringMVC捕获之后就会调用到这个处理器。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//自定义一个异常类</span></span><br><span class="line"><span class="meta">@ResponseStatus(reason = &quot;用户访问异常&quot;, code = HttpStatus.NOT_ACCEPTABLE)</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UserNotFoundInAdminException</span> <span class="keyword">extends</span> <span class="title">RuntimeException</span></span>&#123;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = <span class="number">1L</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;/admin&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">loginAdmin</span><span class="params">(<span class="meta">@RequestParam(&quot;user&quot;)</span>String user)</span></span>&#123;</span><br><span class="line">	<span class="keyword">if</span>(user!=<span class="string">&quot;admin&quot;</span>)&#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> UserNotFoundInAdminException();</span><br><span class="line">    &#125;</span><br><span class="line">    ....</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="3）SimpleMappingExceptionResolver"><a href="#3）SimpleMappingExceptionResolver" class="headerlink" title="3）SimpleMappingExceptionResolver"></a>3）SimpleMappingExceptionResolver</h3><p>用于配置简单的异常解析，可以在SpringMVC的配置文件中配置。其中class为class为<code>SimpleMappingExceptionResolver </code>的全类名，<code>exceptionMappings</code> 属性的key为要处理的异常全类名，value为异常后跳转的视图名；<code>exceptionAttribute</code> 属性的value值为异常信息存储在域的key。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">&quot;org.springframework.web.servlet.handler.SimpleMappingExceptionResolver&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;exceptionMappings&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">props</span>&gt;</span></span><br><span class="line">        	<span class="tag">&lt;<span class="name">prop</span> <span class="attr">key</span>=<span class="string">&quot;java.lang.NullPointerException&quot;</span>&gt;</span>error<span class="tag">&lt;/<span class="name">prop</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">props</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;exceptionAttribute&quot;</span> <span class="attr">value</span>=<span class="string">&quot;ex&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h3 id="4）DefaultHandlerExceptionResolver"><a href="#4）DefaultHandlerExceptionResolver" class="headerlink" title="4）DefaultHandlerExceptionResolver"></a>4）DefaultHandlerExceptionResolver</h3><p>用于处理SpringMVC自带的异常，当没有找到其他的异常解析器时，就会来到这个异常解析器解析。</p>
<h2 id="11、拦截器"><a href="#11、拦截器" class="headerlink" title="11、拦截器"></a>11、拦截器</h2><h3 id="1）概述-1"><a href="#1）概述-1" class="headerlink" title="1）概述"></a>1）概述</h3><p>首先需要区分一些拦截器和过滤器的概念。拦截器是SpringMVC中的一个API设计，而过滤器是Servlet中的一个组件。所有经过Servlet容器的请求都可以被过滤器截获到，而拦截器只对经过DispatcherServlet 处理的请求有效。此外，拦截器通过IoC统一管理，所以可以进行任意注入。</p>
<h3 id="2）配置"><a href="#2）配置" class="headerlink" title="2）配置"></a>2）配置</h3><p>拦截器的核心接口是<code>HandleInterceptor</code> ，自定义的拦截规则要实现该接口，该接口中有三个主要方法，代表着三个执行时机：</p>
<ul>
<li>preHandle：目标方法运行前，返回true则代表放行；</li>
<li>postHandle：目标方法运行后；</li>
<li>afterCompletion：视图响应之后；</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyInterceptor</span> <span class="keyword">implements</span> <span class="title">HandlerInterceptor</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">preHandle</span><span class="params">(HttpServletRequest request,</span></span></span><br><span class="line"><span class="function"><span class="params">                             HttpServletResponse response, </span></span></span><br><span class="line"><span class="function"><span class="params">                             Object handler)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;preHandle.....&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">postHandle</span><span class="params">(HttpServletRequest request,</span></span></span><br><span class="line"><span class="function"><span class="params">                           HttpServletResponse response,</span></span></span><br><span class="line"><span class="function"><span class="params">                           Object handler,</span></span></span><br><span class="line"><span class="function"><span class="params">                           ModelAndView modelAndView)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;postHandle.....&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">afterCompletion</span><span class="params">(HttpServletRequest request,</span></span></span><br><span class="line"><span class="function"><span class="params">                                HttpServletResponse response,</span></span></span><br><span class="line"><span class="function"><span class="params">                                Object handler,</span></span></span><br><span class="line"><span class="function"><span class="params">                                Exception ex)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;afterCompletion.....&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>接着我们需要将拦截器注册到IoC容器中，使用的是<code>&lt;mvc:interceptors&gt;</code>标签，这也说明可以注册多个拦截器；<code>&lt;mvc:interceptor&gt;</code> 标签体内有一个 <code>&lt;mvc:mapping&gt;</code> 用于配置拦截路径，<code> &lt;bean&gt;</code>用于配置拦截器：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">mvc:interceptors</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">mvc:interceptor</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">mvc:mapping</span> <span class="attr">path</span>=<span class="string">&quot;/&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">&quot;top.jtszt.interceptor.MyInterceptor&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">mvc:interceptor</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">mvc:interceptors</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h3 id="3）拦截流程"><a href="#3）拦截流程" class="headerlink" title="3）拦截流程"></a>3）拦截流程</h3><p>从上面我们可以看到拦截器一共有三个运行的时机：目标方法运行前、目标方法运行后、视图响应之后。在配置了拦截器的请求流程大致为：</p>
<ol>
<li>preHandle</li>
<li>目标方法运行</li>
<li>postHandle</li>
<li>视图响应</li>
<li>afterCompletion</li>
</ol>
<h3 id="4）多拦截器"><a href="#4）多拦截器" class="headerlink" title="4）多拦截器"></a>4）多拦截器</h3><p>假设配置了两个拦截器，按照配置顺序第一个记为interceptor1，第二个记为interceptor2。</p>
<p><img src="https://i.loli.net/2021/08/01/4T7owLcrliqf5Ot.png"></p>
<h2 id="12、跨域问题"><a href="#12、跨域问题" class="headerlink" title="12、跨域问题"></a>12、跨域问题</h2><p>跨域指的是当前发起请求的域与该请求指向的资源所在的域不一样，这里的域概念表示的是协议、域名、端口（同源策略）。只有当这三者都相同才属于同一个域。当这三个任一个不相同则会引发跨域问题。</p>
<p>SpringMVC中可以在允许跨域的方法上标注 <code>@CrossOrigin</code> 注解，该注解上可以指定跨域范围。这个注解实际上是给响应头中添加了一个 <code>Access-Control-Allow-Origin: </code> 。</p>
<hr>
<p><em>参考资料：</em></p>
<ul>
<li><a target="_blank" rel="noopener" href="https://docs.spring.io/spring-framework/docs/5.1.3.RELEASE/spring-framework-reference/">Spring Framework 5.1.3.RELEASE文档</a></li>
<li><a target="_blank" rel="noopener" href="https://juejin.cn/book/6857911863016390663/section">从 0 开始深入学习 Spring-掘金小册</a></li>
<li><a target="_blank" rel="noopener" href="https://blog.csdn.net/weixin_42153410/article/details/90753696">浅谈 MVC与三层架构-CSDN</a></li>
<li><a target="_blank" rel="noopener" href="https://blog.csdn.net/u012369373/article/details/77529595?utm_source=tuicool&utm_medium=referral">SpringMVC之视图解析器-CSDN</a></li>
<li><a target="_blank" rel="noopener" href="https://blog.csdn.net/lj1314ailj/article/details/80118372">Spring5 系统架构-CSDN</a></li>
<li><a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1d4411g7tv?p=256">雷丰阳Spring、Spring MVC、MyBatis课程-bilibili</a></li>
</ul>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="mailto:undefined">h0ss</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://blog.gpnusz.cn/2021/08/01/SpringMVC%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">https://blog.gpnusz.cn/2021/08/01/SpringMVC%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://blog.gpnusz.cn" target="_blank">后端学习记录</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/Spring/">Spring</a></div><div class="post_share"></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/2021/08/06/Mybatis%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"><img class="prev-cover" src="https://www.hualigs.cn/image/610c1f94eb0a8.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">Mybatis学习笔记</div></div></a></div><div class="next-post pull-right"><a href="/2021/07/30/Spring%E5%AD%A6%E4%B9%A0-3-AOP/"><img class="next-cover" src="https://www.hualigs.cn/image/610c2015e15b8.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">Spring学习(3)AOP</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span> 相关推荐</span></div><div class="relatedPosts-list"><div><a href="/2022/04/13/【解决方案】细说分片上传与极速秒传-SpringBoot-Vue/" title="【解决方案】细说分片上传与极速秒传(SpringBoot+Vue)"><img class="cover" src="https://i.loli.net/2021/09/01/KHSB3kcFZDQx4vo.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-04-13</div><div class="title">【解决方案】细说分片上传与极速秒传(SpringBoot+Vue)</div></div></a></div><div><a href="/2021/07/30/Spring学习-3-AOP/" title="Spring学习(3)AOP"><img class="cover" src="https://www.hualigs.cn/image/610c2015e15b8.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2021-07-30</div><div class="title">Spring学习(3)AOP</div></div></a></div><div><a href="/2021/07/30/Spring学习-2-IoC/" title="Spring学习(2)IoC"><img class="cover" src="https://www.hualigs.cn/image/610c2015e15b8.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2021-07-30</div><div class="title">Spring学习(2)IoC</div></div></a></div><div><a href="/2021/07/30/Spring学习-1-快速上手/" title="Spring学习(1)快速上手"><img class="cover" src="https://www.hualigs.cn/image/610c2015e15b8.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2021-07-30</div><div class="title">Spring学习(1)快速上手</div></div></a></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="card-info-avatar is-center"><img class="avatar-img" src="/img/avatar.jpg" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/><div class="author-info__name">h0ss</div><div class="author-info__description">一个苦逼后端仔的学习记录</div></div><div class="card-info-data"><div class="card-info-data-item is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">51</div></a></div><div class="card-info-data-item is-center"><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a></div></div><a class="button--animated" id="card-info-btn" target="_blank" rel="noopener" href="https://gitee.com/h0ss"><i class="fab fa-github"></i><span>Gitee仓库</span></a></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn card-announcement-animation"></i><span>公告</span></div><div class="announcement_content">Java后端技术栈语雀文档：https://www.yuque.com/oliver-wdtb1/java</div></div><div class="sticky_layout"><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/11/16/%E7%BB%99%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E6%8F%90%E4%BA%86%E4%B8%AAPR/" title="给开源项目提了个PR">给开源项目提了个PR</a><time datetime="2022-11-15T17:28:40.000Z" title="发表于 2022-11-16 01:28:40">2022-11-16</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/09/03/%E3%80%90MySQL%E3%80%91InnoDB%E7%9A%84%E8%A1%8C%E6%A0%BC%E5%BC%8F/" title="【MySQL】InnoDB的行格式">【MySQL】InnoDB的行格式</a><time datetime="2022-09-02T18:17:38.000Z" title="发表于 2022-09-03 02:17:38">2022-09-03</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/08/21/%E3%80%90Debug%E3%80%91bitField-%E5%BC%95%E5%8F%91%E7%9A%84%E6%A0%88%E6%BA%A2%E5%87%BA%E6%8E%92%E9%94%99%E8%AE%B0/" title="【Debug】bitField 引发的栈溢出排错记">【Debug】bitField 引发的栈溢出排错记</a><time datetime="2022-08-20T18:10:40.000Z" title="发表于 2022-08-21 02:10:40">2022-08-21</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/07/16/%E3%80%90RPC%E3%80%91%E8%AF%A6%E8%A7%A3SPI%E6%9C%BA%E5%88%B6/" title="【RPC】详解SPI机制">【RPC】详解SPI机制</a><time datetime="2022-07-15T18:51:57.000Z" title="发表于 2022-07-16 02:51:57">2022-07-16</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/07/14/%E3%80%90Redis%E3%80%91%E9%87%8D%E8%A6%81%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%9F%BA%E7%A1%80/" title="【Redis】重要数据结构基础">【Redis】重要数据结构基础</a><time datetime="2022-07-13T17:22:08.000Z" title="发表于 2022-07-14 01:22:08">2022-07-14</time></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><div class="js-pjax"></div><script defer="defer" id="fluttering_ribbon" mobile="false" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/canvas-fluttering-ribbon.min.js"></script><script id="canvas_nest" defer="defer" color="0,0,255" opacity="0.7" zIndex="-1" count="99" mobile="false" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/canvas-nest.min.js"></script><script id="click-heart" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/click-heart.min.js" async="async" mobile="false"></script><script id="click-show-text" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/click-show-text.min.js" data-mobile="false" data-text="爱国,敬业,诚信,友善,自由,平等,公正,法治,富强,民主,文明,和谐" data-fontsize="16px" data-random="false" async="async"></script></div></body></html>